﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Security.Principal;
using System.Web.Security;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
using System.Runtime.Serialization;

namespace X.Security
{
    [Serializable]
    public class UserPrincipal : IPrincipal
    {
        [NonSerialized]
        private IUser m_UserInfo;
        private string m_LoginName;
        private IIdentity m_Identity;
        private string[] m_RolesArray;
        [NonSerialized]
        private string m_Roles;
        private string m_UserName;

        public IUser UserInfo
        {
            get { return m_UserInfo; }
            set { m_UserInfo = value; }
        }

        public string LoginName
        {
            get { return m_LoginName; }
            set { m_LoginName = value; }
        }

        public IIdentity Identity
        {
            get { return m_Identity; }
            set { m_Identity = value; }
        }

        public string Roles
        {
            get { return m_Roles; }
            set
            {
                m_Roles = value;
                if (!string.IsNullOrEmpty(value))
                {
                    m_RolesArray = value.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                }
            }
        }

        public string UserName
        {
            get { return m_UserName; }
            set { m_UserName = value; }
        }

        public UserPrincipal() { }

        public UserPrincipal(IIdentity identity)
        {
            if (null == identity)
                throw new ArgumentNullException("identity");
            m_Identity = identity;
        }

        public UserPrincipal(IIdentity identity, string[] roles)
        {
            if (null == identity)
                throw new ArgumentNullException("identity");
            m_Identity = identity;
            if (null != roles)
            {
                m_RolesArray = new string[roles.Length];
                for (int i = 0; i < roles.Length; i++)
                {
                    m_RolesArray[i] = roles[i];
                }
            }
        }

        public static UserPrincipal CreatePrincipal(FormsAuthenticationTicket ticket)
        {
            try
            {
                BinaryFormatter formatter = new BinaryFormatter();
                MemoryStream serializationStream = new MemoryStream(Convert.FromBase64String(ticket.UserData));
                UserPrincipal principal = (UserPrincipal)formatter.Deserialize(serializationStream);
                serializationStream.Dispose();
                principal.Identity = new FormsIdentity(ticket);
                return principal;
            }
            catch (ArgumentNullException)
            {
                return new UserPrincipal(new NoAuthenticateIdentity(), null);
            }
            catch (FormatException)
            {
                return new UserPrincipal(new NoAuthenticateIdentity(), null);
            }
            catch (SerializationException)
            {
                return new UserPrincipal(new NoAuthenticateIdentity(), null);
            }
        }

        public bool IsInRole(string role)
        {
            if (null != role || null != m_RolesArray)
            {
                foreach (string s in role.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
                {
                    for (int i = 0; i < m_RolesArray.Length; i++)
                    {
                        if (!string.IsNullOrEmpty(m_RolesArray[i]) && string.Compare(m_RolesArray[i], s, StringComparison.OrdinalIgnoreCase) == 0)
                        {
                            return true;
                        }
                    }
                }
            }
            return false;
        }

        public string SerializeToString()
        {
            BinaryFormatter formatter = new BinaryFormatter();
            MemoryStream serializationStream = new MemoryStream();
            formatter.Serialize(serializationStream, this);
            string str = Convert.ToBase64String(serializationStream.ToArray());
            serializationStream.Dispose();
            return str;
        }
    }
}
